#if 0
//////////////////////////////////////////////////////////////////////////////////
//                                                                              //
//  This file is part of the buola project (https://code.google.com/p/buola/).  //
//                                                                              //
//  Copyright(c) 2007-2012 Xavi Gratal                                          //
//  gratal AT gmail DOT com                                                     //
//                                                                              //
//  Buola is free software: you can redistribute it and/or modify               //
//  it under the terms of the GNU General Public License as published by        //
//  the Free Software Foundation, either version 3 of the License, or           //
//  (at your option) any later version.                                         //
//                                                                              //
//  Buola is distributed in the hope that it will be useful,                    //
//  but WITHOUT ANY WARRANTY; without even the implied warranty of              //
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the               //
//  GNU General Public License for more details.                                //
//                                                                              //
//  You should have received a copy of the GNU General Public License           //
//  along with buola.  If not, see <http://www.gnu.org/licenses/>.              //
//                                                                              //
//////////////////////////////////////////////////////////////////////////////////

#include <buola/image/algorithm.h>
#include <buola/image/cimageplugin.h>

namespace buola { namespace img {

struct SRGB
{
    unsigned char mBlue;
    unsigned char mGreen;
    unsigned char mRed;
    unsigned char mNull;
} __attribute__ ((packed));

struct SBitmapFileHeader
{
    unsigned short mType;
    long mSize;
    unsigned short mReserved1;
    unsigned short mReserved2;
    long mOffset;
} __attribute__ ((packed));

struct SBitmapInfoHeader
{
    long mSize;
    long mWidth;
    long mHeight;
    short mPlanes;
    short mBitCount;
    long mCompression;
    long mSizeImage;
    long mXppm;
    long mYppm;
    long mClrUsed;
    long mClrImportant;
} __attribute__ ((packed));

struct SIconDirEntry
{
    char mWidth;
    char mHeight;
    char mNumColors;
    char mReserved;
    short mPlanes;
    short mBitCount;
    long mBytes;
    long mOffset;
} __attribute__ ((packed));

struct SIconDir
{
    short mReserved;
    short mType;
    short mCount;
} __attribute__ ((packed));

struct SCursorDirEntry
{
    char mWidth;
    char mHeight;
    char mNumColors;
    char mReserved;
    short mXHot;
    short mYHot;
    long mBytes;
    long mOffset;
} __attribute__ ((packed));

struct SCursorDir
{
    short mReserved;
    short mType;
    short mCount;
} __attribute__ ((packed));

class CBMPCodec : public CCodec
{
public:
    CBMPCodec(bool pIsIco);
    virtual ~CBMPCodec();

    void Read(io::PBufferStream pSrc,CAnyImage &pDst,EImageFormat pFmt,const CSize_i &pSize);
    void Write(const CAnyView &pSrc,io::PBufferStream pDst);

protected:
    void ReadBitmap(img::CImage_rgb8 &pData,io::PBufferStream pStream);
    void ReadMask(io::PBufferStream pStream,uint8_t **pData);

    SBitmapInfoHeader mHeader;
    bool mIsIco;
};

class CBMPPlugin : public CImagePlugin
{
public:
    CBMPPlugin()
    {
        RegisterPlugin("bmp",this);
        RegisterPlugin("BMP",this);
    }

    CCodec *GetInstance()
    {
        return new CBMPCodec(false);
    }
};

class CICOPlugin : public CImagePlugin
{
public:
    CICOPlugin()
    {
        RegisterPlugin("ico",this);
        RegisterPlugin("ICO",this);
    }

    CImageCodec *GetInstance()
    {
        return new CBMPCodec(true);
    }
};

static CBMPPlugin sBMPPlugin;

CBMPCodec::CBMPCodec(bool pIsIco)
    :   mIsIco(pIsIco)
{
}

CBMPCodec::~CBMPCodec()
{
}

void CBMPCodec::ReadImage(img::CImage_rgb8 &pData,io::PBufferStream pStream,const CSize_i& /*pSize*/)
{
    if(!mIsIco)
    {
        SBitmapFileHeader lHeader;

        lHeader.mOffset=0;
        lHeader.mSize=0;

        pStream.read((char*)&lHeader,sizeof(lHeader));

        ReadBitmap(pData,pStream);
    }
    else //mIsIco
    {
        int pW=32,pH=32;

        SIconDir lIconDir;
        pStream.read((char*)&lIconDir,sizeof(lIconDir));

        //check
        if(lIconDir.mReserved!=0||lIconDir.mType!=1||!lIconDir.mCount)
            throw XInternal(I18N("can't read ico image"));

        SIconDirEntry lEntry;
        int lFound=false;

        for(int i=0;i<lIconDir.mCount;i++)
        {
            pStream.read((char*)&lEntry,sizeof(lEntry));
            if(pW==lEntry.mWidth&&pH==lEntry.mHeight)//&&!lEntry.mNumColors)
            {
                lFound=true;
                break;
            }
        }

        if(!lFound)
            throw XInternal(I18N("ico image not found"));

        pStream.seekg(lEntry.mOffset);

        ReadBitmap(pData,pStream);
//TODO_URGENT:      ReadMask(pStream,&lMask);

//      PImage lImage=new CImage;
//      lImage->Create(lData,lMask,CSize_d(mHeader.mWidth,mHeader.mHeight));
    }
}

void CBMPCodec::ReadImage(img::CImage_rgba8 &pData,io::PBufferStream pStream,
                                const CSize_i &pSize)
{
    img::CImage_rgb8 lImage;

    ReadImage(lImage,pStream,pSize);

    pData.Recreate(lImage.Size());

    convert_pixels(lImage,pData);
}

void CBMPCodec::ReadImage(img::CImage_gray8 &pData,io::PBufferStream pStream,
                                const CSize_i &pSize)
{
    img::CImage_rgb8 lImage;

    ReadImage(lImage,pStream,pSize);

    pData.Recreate(lImage.Size());

    convert_pixels(lImage,pData);
}

void CBMPCodec::WriteImage(const img::CView_rgb8&,io::PBufferStream)
{
}

void CBMPCodec::WriteImage(const img::CView_gray8&,io::PBufferStream)
{
}

void CBMPCodec::WriteImage(const img::CView_rgba8&,io::PBufferStream)
{
}

void CBMPCodec::ReadBitmap(img::CImage_rgb8 &pData,io::PBufferStream pStream)
{
    pStream.read((char*)&mHeader,sizeof(mHeader));

    if(mIsIco) mHeader.mHeight/=2;

    int lSrcWidth=mHeader.mWidth+mHeader.mWidth%2;

    SRGB lColorTable[256];
    unsigned char lOriginal[mHeader.mWidth*mHeader.mHeight];

    pData.Recreate(CSize_i(mHeader.mWidth,mHeader.mHeight));

    pStream.read((char*)lColorTable,sizeof(SRGB)*(mHeader.mClrUsed?:(1<<mHeader.mBitCount)));
    pStream.read((char*)lOriginal,mHeader.mWidth*mHeader.mHeight);

    int lColor;

    const img::CMView_rgb8 &lView=pData;

    if(mHeader.mBitCount==4)
    {
        for(int i=0;i<mHeader.mHeight;i++)
        {
            for(int j=0;j<mHeader.mWidth;j+=2)
            {
                lColor=(lOriginal[((mHeader.mHeight-1-i)*lSrcWidth+j)/2]&0xf0)>>4;
                memcpy(&lView(j,i),&lColorTable[lColor],3);
                lColor=lOriginal[((mHeader.mHeight-1-i)*lSrcWidth+j)/2]&0x0f;
                memcpy(&lView(j+1,i),&lColorTable[lColor],3);
            }
        }
    }
    else if(mHeader.mBitCount==8)
    {
        for(int i=0;i<mHeader.mHeight;i++)
        {
            for(int j=0;j<mHeader.mWidth;j++)
            {
                memcpy(&lView(j,i),&lColorTable[lOriginal[(mHeader.mHeight-1-i)*lSrcWidth+j]],3);
            }
        }
    }
}

void CBMPCodec::ReadMask(io::PBufferStream /*pStream*/,uint8_t** /*pMask*/)
{
//TODO_URGENT:
#if 0
    char lMask[(mHeader.mHeight*mHeader.mWidth)>>3];

    pStream->Read(lMask,(mHeader.mHeight*mHeader.mWidth)>>3);
    *pMask=alloc_array<unsigned char>((mHeader.mHeight*mHeader.mWidth)>>3);
    int lLineWidth=mHeader.mWidth>>3;

    for(int i=0;i<mHeader.mHeight;i++)
    {
        memcpy(&((*pMask)[i*lLineWidth]),&lMask[(mHeader.mHeight-i-1)*lLineWidth],lLineWidth);
        for(int j=0;j<lLineWidth;j++)
        {
            (*pMask)[i*lLineWidth+j]=~((*pMask)[i*lLineWidth+j]);
        }
    }

    ConvertSwapBits(*pMask,lLineWidth*mHeader.mHeight);
#endif
}

/*namespace img*/ } /*namespace buola*/ }
#endif